package groove;

import groove.json.request.CommunicationTokenRequest;
import groove.json.request.IGrooveRequest;
import groove.json.request.InitiateSessionRequest;
import groove.json.request.MarkSongDownloadedRequest;
import groove.json.request.ResultsFromSearchRequest;
import groove.json.request.StreamKeyFromSongIDRequest;
import groove.json.response.CommunicationTokenResponse;
import groove.json.response.IGrooveResponse;
import groove.json.response.InitiateSessionResponse;
import groove.json.response.MarkSongDownloadedResponse;
import groove.json.response.ResultsFromSearchResponse;
import groove.json.response.StreamKeyFromSongIDResponse;
import groove.json.response.result.StreamKeyFromSongIDResult;
import groove.json.util.SearchResult;
import groove.json.util.SongInfo;
import groove.util.CryptHelper;
import groove.util.GrooveConstants;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.UUID;

import com.google.gson.Gson;


public class GrooveClient {

	private String myUserID;
	private String mySessionID;
	private String mySecretKey;
	private String myCommunicationToken;
	
	private String grooveurl = GrooveConstants.URL_STANDARD;
	private String savegrooveurl = GrooveConstants.URL_SECURE;
	
	
	public GrooveClient(){
		myUserID = UUID.randomUUID().toString().toUpperCase();
        mySessionID = getSessionID();
        mySecretKey = CryptHelper.GetMD5Hash(mySessionID);
        myCommunicationToken = getCommunicationToken();
	}
	
	public URLConnection getSongStream(SongInfo info) throws IOException {
		StreamKeyFromSongIDResult result = getStreamKeyFromSongIDParameters(info.getSongID());
		String streamServerID = result.getIp();
		String streamKey = result.getStreamKey();
		
		URL url = new URL("http://" + streamServerID + "/stream.php?");
        String data = "streamKey=" + streamKey;
        
        URLConnection conn = url.openConnection();
        conn.setDoOutput(true);
        OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
        wr.write(data);
        wr.flush();
        
//        InputStream input = conn.getInputStream();
        
        if(!markSongDownloaded(streamServerID, streamKey, info.getSongID())){
        	System.err.println("\n\t\tERROR! MarkSongDownloaded returned FALSE!!!");
        }
        return conn;
    }
	
	public SearchResult getResultsFromSearch(String query){
		ResultsFromSearchRequest request = new ResultsFromSearchRequest(this, query);
		ResultsFromSearchResponse response = (ResultsFromSearchResponse) callMethod(request, ResultsFromSearchResponse.class);
		return response.getSearchResult();
	}
	
	private boolean markSongDownloaded(String streamServerID, String streamKey, long songID){
		MarkSongDownloadedRequest request = new MarkSongDownloadedRequest(this, streamKey, streamServerID, songID);
		MarkSongDownloadedResponse response = (MarkSongDownloadedResponse)callMethod(request, MarkSongDownloadedResponse.class);
		return response.getReturn();
	}
	
	private StreamKeyFromSongIDResult getStreamKeyFromSongIDParameters(long songID){
		StreamKeyFromSongIDRequest request = new StreamKeyFromSongIDRequest(this, songID);
		StreamKeyFromSongIDResponse response = (StreamKeyFromSongIDResponse) callMethod(request, StreamKeyFromSongIDResponse.class);
		return response.getResult();
	}

	private String getCommunicationToken() {
		CommunicationTokenRequest request = new CommunicationTokenRequest(this);
		CommunicationTokenResponse response = (CommunicationTokenResponse) callMethod(request, CommunicationTokenResponse.class);
		return response.getCommunicationToken();
	}
	
	private String getSessionID() {
		InitiateSessionRequest request = new InitiateSessionRequest();
		InitiateSessionResponse response = (InitiateSessionResponse) callMethod(request, InitiateSessionResponse.class);
		return response.getSessionID();
	}
	
	private IGrooveResponse callMethod(IGrooveRequest request, Class<?> responseType){
		
		IGrooveResponse response = null;
		
		try {
			String address = null;
			if(request.isHTTPS()){
				address = savegrooveurl;
			}
			else{
				address = grooveurl;
			}
			URLConnection conn = (new URL(address + request.getMethod())).openConnection();
			conn.setConnectTimeout(5000);
			conn.setDoOutput(true);
			conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 GTB7.0 (.NET CLR 3.5.30729)");
			conn.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
			conn.setRequestProperty("Content-Type", "text/html; charset=UTF-8");
			conn.setRequestProperty("Accept-Language", "de-de,de;q=0.8,en-us;q=0.5,en;q=0.3");
			conn.setRequestProperty("Accept-Charset", "utf-8;q=0.7,*;q=0.7");
			
			String requestString = (new Gson()).toJson(request);
			System.out.println("\n\nREQUEST (" + request.getMethod() + "):\n\n\t" + requestString);
			
			OutputStreamWriter outputstreamwriter = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
	        outputstreamwriter.write(requestString);
	        outputstreamwriter.flush();
	        outputstreamwriter.close();
	        
	        BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            String responseString = "";
            while ((line = rd.readLine()) != null) {
                responseString += line;
            }
            rd.close();
            
            response = (IGrooveResponse) (new Gson()).fromJson(responseString, responseType);
            System.out.println("\n\nRESPONSE (" + request.getMethod() + "):\n\n\t" + responseString);
            
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return response;
	}
	
	public String getMyUserID() {
		return myUserID;
	}

	public String getMySessionID() {
		return mySessionID;
	}

	public String getMySecretKey() {
		return mySecretKey;
	}

	public String getMyCommunicationToken() {
		return myCommunicationToken;
	}
}
